
#include "application.h"
#include <event/events.h>
#include <base/resourcemanager.h>
#include <scene/SceneManager.h>
#include <scene/Quad.h>
#include <scene/ShaderNode.h>
#include <scene/GeometryNodes.h>
#include <scene/line.h>
#include <input/inputhandler.h>
#include <base/directorymanager.h>

#include <list>

bool run_application;
bool show_grid = true;
long center_x = 0;
long center_y = 0;
float view_scale = 1.0;
long view_width = 1;
long view_height = 1;
SceneNode linenode;
Perspective sizeroot;
Matrix root;
std::list<Line*> gridlines;
TextureNode rooms;
long texture;

unsigned long current_tool = TOOL_VIEW;
long mouse_x;
long mouse_y;

void SetView(){
  D3DXMATRIX mscale;
  D3DXMATRIX mtranslate;

  sizeroot.width = view_width;
  sizeroot.height = view_height;

  D3DXMatrixTranslation(&mtranslate, -center_x, -center_y, 0);
  D3DXMatrixScaling(&mscale, view_scale, (view_scale*view_width/view_height), 1.0);
  root.matrix = mscale * mtranslate;
}

void SetLines(){
  Line * line;
  linenode.removeAll();
  char temp[128];
  for(std::list<Line*>::iterator i = gridlines.begin(); i != gridlines.end(); i++){
    delete *i;
  }
  for(int i = center_x - view_width / 2; i < center_x + view_width / 2; i+=64*1024){
    line = new Line(i, center_y + view_height / 2, i, center_y - view_height / 2);
    gridlines.push_back(line);
    linenode.addChild(line);
    sprintf(temp, "hrzn %d, %d", i, center_y + view_height / 2);
    //events::Fire(new events::PrintConsole(temp));
  }
  for(int i = center_y - view_height / 2; i < center_y + view_height / 2; i+=64*1024){
    line = new Line(center_x + view_width / 2, i, center_x - view_width / 2, i);
    gridlines.push_back(line);
    linenode.addChild(line);
    sprintf(temp, "vert %d, %d", center_x + view_width / 2, i);
    //events::Fire(new events::PrintConsole(temp));
  }
}

void SetRooms(Controller & c){
  rooms.destroyChildren();
  for(int i = 0; i < c.stage->rooms.size(); i++){
    Room * r = &c.stage->rooms[i];
    rooms.addChild(new Quad(r->origin_x, r->origin_y, r->width, r->height, 0.0));
  }
}

DWORD WINAPI RunApplication(LPVOID window) {

  const events::Event * event;
  run_application = true;

  Controller controller;
  //Line xaxis(-0.5,0,1,0);
  //Line xaxis2(-0.5,0.1,1,0.1);
  rooms.color = 0xffff0000;
  //texture = LoadResource(RM_TEXTURE, "graphics/you_blue.png", controller);
  //rooms.texture = ((Texture *)GetResource(texture))->getTexture();
  
  //TODO: initialize
  events::Fire(new events::PrintConsole("Application thread initialized"));

  unsigned long lasttime = GetTickCount();

  unsigned long tdiff = 0;

  //SetView();
  //SetLines();
  sizeroot.addChild(&root);
  root.addChild(&rooms);
  //root.addChild(&xaxis);
  //root.addChild(&xaxis2);

  while(run_application){
    //root.removeAll();
    while(event = events::PeekEvent(events::APP_QUEUE)){
      HandleEvent(event, controller);
      events::PopEvent(events::APP_QUEUE);
    }

    tdiff = GetTickCount() - lasttime;
    lasttime += tdiff;
    //if(show_grid){ 
    //  root.addChild(&linenode);
    //}
    CopyGraph(&sizeroot, GetDevice(0));
  }

  //TODO: clean up
  return S_OK;
}

long HandleEvent(const events::Event * event, Controller & c) {
  
  char temp[256];
  int result;

  if(!event)
    return 0;

  const char * type = event->type();
  if(events::CompareEvents(type, events::ENDTHREAD_EVENT)){
    events::Fire(new events::PrintConsole("Exiting application thread"));
    run_application = false;
    return 0;

  } else if(events::CompareEvents(type, STAGE_FILE_EVENT)){
    int t = ((StageFileEvent *)event)->action();
    switch(t){
      case STAGE_NEW:
        c.newStage();
        break;
      case STAGE_LOAD:
        result = c.loadStage(((StageFileEvent *)event)->file());
        SetRooms(c);
        sprintf(temp, "load result: %d", result);
        events::Fire(new events::PrintConsole(temp));
        break;
      case STAGE_SAVE:
        c.saveStageToFile(((StageFileEvent *)event)->file());
        break;
    }
    return 0;

  } else if(events::CompareEvents(type, APP_OPTION_EVENT)) {
    switch(((AppOptionEvent *)event)->option){
      case OPTION_GRID:
        show_grid = ((AppOptionEvent *)event)->value;
    }
  } else if(events::CompareEvents(type, APP_MOUSE_EVENT)) {
    MouseEvent * me = (MouseEvent *)event;
    mouse_x = me->x;
    mouse_y = me->y;
    if(me->button){
      SceneNode * s = sizeroot.select(D3DXVECTOR4(me->x, me->y, 0, 1));
      sprintf(temp, "click on %x", s);
      events::Fire(new events::PrintConsole(temp));
      if(s)
        ((Quad *)s)->x -= 1024;
    //sprintf(temp, "mouse at %f, %f, button: %d", me->x, me->y, me->button);
    //events::Fire(new events::PrintConsole(temp));
    }
  } else if(events::CompareEvents(type, APP_TOOL_EVENT)) {
    current_tool = ((ToolEvent *)event)->tool;
  } else if(events::CompareEvents(type, APP_VIEW_EVENT)) {
    ViewEvent * vi = (ViewEvent *)event;
    view_scale = vi->scale;
    view_width = vi->width * 1024;
    view_height = vi->height * 1024;
    center_x = vi->x * 1024;
    center_y = vi->y * 1024;
    SetView();
    SetLines();
  }
  return 0;
}

long LoadResource(unsigned long type, const std::string & filename, Controller & c) {
  bool got_index = false;
  const events::Event * event = NULL;

  events::Fire(new events::LoadResource(type, filename));
  while(!got_index) {  
    event = events::PeekEvent(events::APP_QUEUE);
    if(event) {     
      if(events::CompareEvents(event->type(), events::REPORTRESOURCEID_EVENT)) {
        got_index = true;
      } else {
        HandleEvent(event, c);
        events::PopEvent(events::APP_QUEUE);
      }
    }
  }

  long index = ((events::ReportResourceID *)event)->getIndex();
  events::PopEvent(events::APP_QUEUE);
  return index;
}

